/**
 * @author Federico Consoli
 *
 * Released under GNU GPLv3 (http://www.gnu.org/licenses/gpl-3.0.txt)
 */

#include "client_fun.h"
using namespace std;

Fun::Fun( string client_name,string ip, unsigned short porta):Client(client_name) {
    cout << display() + "Building class Fun...\n";
    ip_reg = ip;
    port_reg = porta;
    name = client_name;
    load_list_img();
    cout << "Class Fun build\n";
}

void Fun::load_list_img() {
    list_of_jpg.clear();
    struct dirent **namelist;
    int n;
    string temp;
    string::size_type found;
    n = scandir(".", &namelist, 0, alphasort);
    if (n < 0) cout << "Error! " << endl;
    else
        while (n--) {
            temp.assign(namelist[n]->d_name);
            found = temp.find_last_of(".\\");
            if ((temp.substr(found + 1)) == "jpg" && temp.size() > 4)
                list_of_jpg.push_back(temp);
            free(namelist[n]);
        }
    free(namelist);
    if (list_of_jpg.size() == 0)
        cout << "\nNo image found in the directory\n";
    else {
        ostringstream out;
        out << "Image in the local directory '";
        for (string::size_type i = 0; i < list_of_jpg.size(); i++)
            out << list_of_jpg.at(i) << " ";
        cout << display() + out.str() + "' \n";
    }
}

void Fun::menu() {
    int quit = 0;
    string name;
    int gradi;
    int rewrite;
    int scelta;
    while (!quit) {
        cout << "\n--------------- [CLIENT - MENU] ---------------\n";
        cout << "0 - Exit\n";
        cout << "1 - Rotate Image\n";
        cout << "2 - Horizontal Flip image\n";
        cout << "3 - Store image\n";
        cout << "4 - Get image\n";
        cout << "5 - Get list image (remote)\n";
        cout << "6 - Local image list\n";
        
        cout << "--------------- [CLIENT - MENU] ---------------\n";
        cout << "> ";
        cin >> scelta;
        switch (scelta) {
            case 0:
                quit = 1;
                break;
            case 1:
                cout << "Enter the name of the image to rotate\n";
                cin >> name;
                cout << "Enter the number of degrees\n";
                cin >> gradi;
                cout << "Do you want to overwrite the original image? 1 = Yes 0 = No\n";
                cin >> rewrite;
                rotate_img(name, gradi, rewrite);
                break;
            case 2:
                cout << "Enter the name of which produce the mirror image\n";
                cin >> name;
                cout << "Do you want to overwrite the original image? 1 = Yes 0 = No\n";
                cin >> rewrite;
                orizflip(name, rewrite);
                break;
            case 3:
                cout << "Enter the name of the image to be stored on the Service Provider\n";
                cin >> name;
                store_img(name);
                break;
            case 4:
                cout << "Enter the name of the image to be taken in the Service Providers\n";
                cin >> name;
                get_img(name);
                break;
            case 5:
                get_list();
                break;
            case 6:
                load_list_img();
                break;
            default:
                cout << "Unrecognized command number\n";
                break;
        }
    }
}

void Fun::random_fun() {
    unsigned int num_fun;
    string single_name;
    if (list_of_jpg.size() == 0) {
        cout << display() + "No image found in the directory\n";
        num_fun = 0;
    } else
        num_fun = rand() % 2;
    //Carico un immagine dal server e la salvo localmente
    if (num_fun == 0) {
        //Prelevo la lista dal server e la metto in un vettore di stringhe
        string lista_img = get_list();
        if (lista_img == "") return;
        istringstream list_par(lista_img);
        vector<string> lista;
        while (list_par >> single_name)
            lista.push_back(single_name);
        num_fun = rand() % lista.size(); //numero random di dimensione massima della lsita
        single_name = lista.at(num_fun); //Estraggo il nome dell'immagine
       get_img(single_name);
        // if (get_img(single_name) == 0)/*Controllo?*/; //Immagine sempre presente, controllo inutile dato che se un immagine è in lista è sicuramente
        //sul server dato che nessuno la può cancellare. utile per sviluppi futuri
    }        //Leggo da disco un immagine  a caso e la invio al server
    else if (num_fun == 1) {
        num_fun = rand() % list_of_jpg.size();
        single_name = list_of_jpg.at(num_fun);
        // store_img(string single_name);  //Bisogna memorizzarli in file temporanei?
    }
    //Ora l'immagine è su disco
    num_fun = rand() % 2; //Estraggo un numero a caso tra 0 e 1
    //Se è 0 chiedi la rotazione
    if (num_fun == 0) {
        int rotate_angle = rand() % 360; //Angolo a caso
        rotate_img(single_name, rotate_angle, 1, 1);
    }
    //Se è uno chiedi il flip
    if (num_fun == 1) {
        orizflip(single_name);
    }
    store_img(single_name); //La memorizzo sul services
    load_list_img();
}

int Fun::orizflip(string name, int sovrascrivi) {
    cout << display() + "Orizzontal flip of image " + name+ " started\n";
    int sock;
    string out_file_name;
    struct stat stFileInfo;
    if (sovrascrivi == 1)
        out_file_name = "";
    else {
        ostringstream out;
        out << "horiz_flip_";
        out_file_name = out.str();
    }
    if (stat(name.c_str(), &stFileInfo)) {
        cout << display() + "File does not exist or you do not have permission to read\n";
        return -1;
    }
    out_file_name.append(name); //horiz_flip_name.jpg
    Service::servizio *richiesta = aggiungi_servizio("Horizontal Flip image", "buffer", "buffer", 0, "");
    if (richiedi_servizio(richiesta)) {
        Response R;
        R.crea_resp(richiesta);
        Response::valori*pacchetto_uscita = R.pacchetto_vuoto("in");
        char *membloc;
        int len;
        Connection::file_to_string(membloc, name.c_str(), len);
        pacchetto_uscita->buffer[0] = membloc;
        pacchetto_uscita->bufflen[0] = len;
        sock = Connection::connect_to(richiesta->ip, richiesta->port);
        if (sock == -1)
            throw 17;
        invia_servizio(richiesta, sock);
        R.invia_pacchetto(pacchetto_uscita, sock, "in");
        Response::valori*val_in = R.ricevi_pacchetto(sock, "out");
        Connection::string_to_file(val_in->buffer[0], out_file_name.c_str(), val_in->bufflen[0]);
         if (sovrascrivi == 0)
            cout << display() + "The name of the Horizontal Flip image is -> " + out_file_name + '\n';
            
        close(sock);
        R.rem_val(pacchetto_uscita, "in");
        R.rem_val(val_in, "out");
    }
    rimuovi_servizio(richiesta->nome_servizio, richiesta->ip, richiesta->port);
    cout << display() + "Horizzontal flip of image: " + name+ " end\n";
    return 0;
}

int Fun::rotate_img(string name, int value, int sovrascrivi, int crop_enable) {
    ostringstream out;
    out << value;
    cout << display() + "Rotate image started of: " + name + " degrees: " + out.str() + '\n';
    struct stat stFileInfo;
    int sock;
    string out_file_name;
    if (sovrascrivi == 1)
        out_file_name = "";
    else {
        ostringstream out;
        out << "rotate_" << value << "_";
        out_file_name = out.str();
    }
    out_file_name.append(name);
    if (value < 1 || value > 359) {
        cout << "Invalid degrees\n";
        return -1;
    }
    if (stat(name.c_str(), &stFileInfo)) {
        cout << "File does not exist or you do not have permission to read\n";
        return -1;
    }
    Service::servizio *richiesta = aggiungi_servizio("Rotate image", "int buffer", "buffer", 0, "");
    if (richiedi_servizio(richiesta)) {
        Response R;
        R.crea_resp(richiesta);
        Response::valori*pacchetto_uscita = R.pacchetto_vuoto("in");
        char *membloc;
        int len;
        Connection::file_to_string(membloc, name.c_str(), len);
        pacchetto_uscita->buffer[0] = membloc;
        pacchetto_uscita->bufflen[0] = len;
        pacchetto_uscita->array[0] = value;
        sock = Connection::connect_to(richiesta->ip, richiesta->port);
        if (sock == -1)
            throw 18;
        invia_servizio(richiesta, sock);
        Connection::send_int(crop_enable, sock);
        R.invia_pacchetto(pacchetto_uscita, sock, "in");
        Response::valori*val_in = R.ricevi_pacchetto(sock, "out");
        Connection::string_to_file(val_in->buffer[0], out_file_name.c_str(), val_in->bufflen[0]);
        if (sovrascrivi == 0)
            cout << display() + "The name of the rotated image is -> " + out_file_name + '\n';
        close(sock);
        R.rem_val(pacchetto_uscita, "in");
        R.rem_val(val_in, "out");
    }
    rimuovi_servizio(richiesta->nome_servizio, richiesta->ip, richiesta->port);
    cout << display() + "Rotate image of: " + name + " end\n";
    return 0;
}

int Fun::store_img(string name) {
    cout << display() + "Store image of " + name + " started\n";
    struct stat stFileInfo;
    if (stat(name.c_str(), &stFileInfo)) {
        cout << "File " + name + " does not exist or you do not have permission to read\n";
        return -1;
    }
    int sock;
    string risposta;
    Service::servizio *richiesta = aggiungi_servizio("Store image", "string buffer", "", 0, "");
    if (richiedi_servizio(richiesta)) {
        Response R;
        R.crea_resp(richiesta);
        Response::valori*pacchetto_uscita = R.pacchetto_vuoto("in");
        char *membloc;
        int len;
        Connection::file_to_string(membloc, name.c_str(), len);
        pacchetto_uscita->str[0] = name;
        pacchetto_uscita->buffer[0] = membloc;
        pacchetto_uscita->bufflen[0] = len;
        sock = Connection::connect_to(richiesta->ip, richiesta->port);
        if (sock == -1)
            throw 19;
        invia_servizio(richiesta, sock);
        R.invia_pacchetto(pacchetto_uscita, sock, "in");
        Connection::recv_s(risposta, sock);
        close(sock);
        R.rem_val(pacchetto_uscita, "in");
        cout << display() + risposta + '\n';
    }
    rimuovi_servizio(richiesta->nome_servizio, richiesta->ip, richiesta->port);
    cout << display() + "Store image of " + name + " end\n";
    return 0;
}

int Fun::get_img(string name) {
    cout << display() + "Get image of " + name + " started\n";
    int sock;
    string risposta;
    int ret = -1;
    Service::servizio *richiesta = aggiungi_servizio("Get image", "string", "buffer", 0, "");
    if (richiedi_servizio(richiesta)) {
        Response R;
        R.crea_resp(richiesta);
        Response::valori*pacchetto_uscita = R.pacchetto_vuoto("in");
        pacchetto_uscita->str[0] = name;
        sock = Connection::connect_to(richiesta->ip, richiesta->port);
        if (sock == -1)
            throw 20;
        invia_servizio(richiesta, sock);
        R.invia_pacchetto(pacchetto_uscita, sock, "in");
        Connection::recv_s(risposta, sock);
        if (risposta == "Found") {
            Response::valori*val_in = R.ricevi_pacchetto(sock, "out");
            Connection::string_to_file(val_in->buffer[0], name.c_str(), val_in->bufflen[0]);
            cout << display() + "Received image: " + name.c_str() + '\n';
            R.rem_val(val_in, "out");
            ret = 1;
        } else {
            cout << display() + "Image " + name.c_str() + " not present\n";
            ret = 0;
        }
        R.rem_val(pacchetto_uscita, "in");
        close(sock);
    }
    rimuovi_servizio(richiesta->nome_servizio, richiesta->ip, richiesta->port);
    cout << display() + "Get image of " + name + " end\n";
    return ret;
}

string Fun::get_list() {
    cout << display() + "Get list started\n";
    int sock;
    string risposta;
    Service::servizio *richiesta = aggiungi_servizio("Get list", "", "", 0, "");
    if (richiedi_servizio(richiesta)) {
        sock = Connection::connect_to(richiesta->ip, richiesta->port);
        if (sock == -1)
            throw 21;
        invia_servizio(richiesta, sock);
        Connection::recv_s(risposta, sock);
        if (risposta != "")
            cout << display() + "Image list is '" + risposta + "' \n";
        else
            cout << display() + "Image list is empty\n";
    }
    rimuovi_servizio(richiesta->nome_servizio, richiesta->ip, richiesta->port);
    cout << display() + "Get list finished\n";
    return risposta;
}


